Skip to content

Commit

Permalink
Part 16
Browse files Browse the repository at this point in the history
  • Loading branch information
nicklockwood committed Apr 25, 2020
1 parent 04ab7ac commit 3a5771d
Show file tree
Hide file tree
Showing 17 changed files with 222 additions and 15 deletions.
7 changes: 3 additions & 4 deletions Source/Engine/Color.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ public extension Color {
static let clear = Color(r: 0, g: 0, b: 0, a: 0)
static let black = Color(r: 0, g: 0, b: 0)
static let white = Color(r: 255, g: 255, b: 255)
static let gray = Color(r: 192, g: 192, b: 192)
static let red = Color(r: 255, g: 0, b: 0)
static let green = Color(r: 0, g: 255, b: 0)
static let blue = Color(r: 0, g: 0, b: 255)
static let red = Color(r: 217, g: 87, b: 99)
static let green = Color(r: 153, g: 229, b: 80)
static let yellow = Color(r: 251, g: 242, b: 54)
}
4 changes: 4 additions & 0 deletions Source/Engine/Texture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,8 @@ public enum Texture: String, CaseIterable {
case switch1, switch2, switch3, switch4
case elevatorFloor, elevatorCeiling, elevatorSideWall, elevatorBackWall
case medkit
case crosshair
case healthIcon
case pistolIcon, shotgunIcon
case font
}
7 changes: 5 additions & 2 deletions Source/Engine/Weapon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public extension Weapon {
let projectiles: Int
let spread: Double
let defaultAmmo: Double
public let hudIcon: Texture
}

var attributes: Attributes {
Expand All @@ -34,7 +35,8 @@ public extension Weapon {
cooldown: 0.25,
projectiles: 1,
spread: 0,
defaultAmmo: .infinity
defaultAmmo: .infinity,
hudIcon: .pistolIcon
)
case .shotgun:
return Attributes(
Expand All @@ -45,7 +47,8 @@ public extension Weapon {
cooldown: 0.5,
projectiles: 5,
spread: 0.4,
defaultAmmo: 5
defaultAmmo: 10,
hudIcon: .shotgunIcon
)
}
}
Expand Down
21 changes: 21 additions & 0 deletions Source/Rampage/Assets.xcassets/crosshair.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "crosshair.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions Source/Rampage/Assets.xcassets/font.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "font.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions Source/Rampage/Assets.xcassets/healthIcon.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "healthIcon.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions Source/Rampage/Assets.xcassets/pistolIcon.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "pistolIcon.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions Source/Rampage/Assets.xcassets/shotgunIcon.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "shotgunIcon.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion Source/Rampage/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@
<array>
<string>armv7</string>
</array>
<key>UIStatusBarHidden</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
Expand Down
9 changes: 9 additions & 0 deletions Source/Rampage/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ class ViewController: UIViewController {
tapGesture.delegate = self
}

override var prefersStatusBarHidden: Bool {
return true
}

private var inputVector: Vector {
switch panGesture.state {
case .began, .changed:
Expand Down Expand Up @@ -129,6 +133,11 @@ class ViewController: UIViewController {

let width = Int(imageView.bounds.width), height = Int(imageView.bounds.height)
var renderer = Renderer(width: width, height: height, textures: textures)
let insets = self.view.safeAreaInsets
renderer.safeArea = Rect(
min: Vector(x: Double(insets.left), y: Double(insets.top)),
max: renderer.bitmap.size - Vector(x: Double(insets.left), y: Double(insets.bottom))
)
renderer.draw(world)

imageView.image = UIImage(bitmap: renderer.bitmap)
Expand Down
45 changes: 37 additions & 8 deletions Source/Renderer/Bitmap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ public struct Bitmap {
}

public extension Bitmap {
var size: Vector {
return Vector(x: Double(width), y: Double(height))
}

subscript(x: Int, y: Int) -> Color {
get { return pixels[x * height + y] }
set {
Expand Down Expand Up @@ -69,32 +73,57 @@ public extension Bitmap {
}
}

mutating func drawColumn(_ sourceX: Int, of source: Bitmap, at point: Vector, height: Double) {
mutating func drawColumn(
_ sourceX: Int,
of source: Bitmap,
at point: Vector,
height: Double,
tint: Color? = nil
) {
let start = Int(point.y), end = Int((point.y + height).rounded(.up))
let stepY = Double(source.height) / height
let offset = Int(point.x) * self.height
if source.isOpaque {
for y in max(0, start) ..< min(self.height, end) {
let sourceY = max(0, Double(y) - point.y) * stepY
let sourceColor = source[sourceX, Int(sourceY)]
var sourceColor = source[sourceX, Int(sourceY)]
if let tint = tint {
sourceColor.r = UInt8(UInt16(sourceColor.r) * UInt16(tint.r) / 255)
sourceColor.g = UInt8(UInt16(sourceColor.g) * UInt16(tint.g) / 255)
sourceColor.b = UInt8(UInt16(sourceColor.b) * UInt16(tint.b) / 255)
sourceColor.a = UInt8(UInt16(sourceColor.a) * UInt16(tint.a) / 255)
}
pixels[offset + y] = sourceColor
}
} else {
for y in max(0, start) ..< min(self.height, end) {
let sourceY = max(0, Double(y) - point.y) * stepY
let sourceColor = source[sourceX, Int(sourceY)]
var sourceColor = source[sourceX, Int(sourceY)]
if let tint = tint {
sourceColor.r = UInt8(UInt16(sourceColor.r) * UInt16(tint.r) / 255)
sourceColor.g = UInt8(UInt16(sourceColor.g) * UInt16(tint.g) / 255)
sourceColor.b = UInt8(UInt16(sourceColor.b) * UInt16(tint.b) / 255)
sourceColor.a = UInt8(UInt16(sourceColor.a) * UInt16(tint.a) / 255)
}
blendPixel(at: offset + y, with: sourceColor)
}
}
}

mutating func drawImage(_ source: Bitmap, at point: Vector, size: Vector) {
mutating func drawImage(
_ source: Bitmap,
xRange: Range<Int>? = nil,
at point: Vector,
size: Vector,
tint: Color? = nil
) {
let xRange = xRange ?? 0 ..< source.width
let start = Int(point.x), end = Int(point.x + size.x)
let stepX = Double(source.width) / size.x
for x in max(0, start) ..< min(width, end) {
let sourceX = (Double(x) - point.x) * stepX
let stepX = Double(xRange.count) / size.x
for x in max(0, start) ..< max(0, start, min(width, end)) {
let sourceX = Int(max(0, Double(x) - point.x) * stepX) + xRange.lowerBound
let outputPosition = Vector(x: Double(x), y: point.y)
drawColumn(Int(sourceX), of: source, at: outputPosition, height: size.y)
drawColumn(sourceX, of: source, at: outputPosition, height: size.y, tint: tint)
}
}

Expand Down
57 changes: 57 additions & 0 deletions Source/Renderer/Renderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ private let fizzle = (0 ..< 10000).shuffled()
public struct Renderer {
public private(set) var bitmap: Bitmap
private let textures: Textures
public var safeArea: Rect

public init(width: Int, height: Int, textures: Textures) {
self.bitmap = Bitmap(width: width, height: height, color: .black)
self.textures = textures
self.safeArea = Rect(min: Vector(x: 0, y: 0), max: bitmap.size)
}
}

Expand Down Expand Up @@ -134,6 +136,61 @@ public extension Renderer {
size: Vector(x: weaponWidth, y: screenHeight)
)

// Crosshair
let crosshair = textures[.crosshair]
let hudScale = bitmap.size.y / 64
let crosshairSize = crosshair.size * hudScale
bitmap.drawImage(crosshair, at: (bitmap.size - crosshairSize) / 2, size: crosshairSize)

// Health icon
let healthIcon = textures[.healthIcon]
var offset = safeArea.min + Vector(x: 1, y: 1) * hudScale
bitmap.drawImage(healthIcon, at: offset, size: healthIcon.size * hudScale)
offset.x += healthIcon.size.x * hudScale

// Health
let font = textures[.font]
let charSize = Vector(x: font.size.x / 10, y: font.size.y)
let health = Int(max(0, world.player.health))
let healthTint: Color
switch health {
case ...10:
healthTint = .red
case 10 ... 30:
healthTint = .yellow
default:
healthTint = .green
}
for char in String(health) {
let index = Int(char.asciiValue!) - 48
let step = Int(charSize.x)
let xRange = index * step ..< (index + 1) * step
bitmap.drawImage(
font,
xRange: xRange,
at: offset,
size: charSize * hudScale,
tint: healthTint
)
offset.x += charSize.x * hudScale
}

// Ammunition
offset.x = safeArea.max.x
let ammo = Int(max(0, min(99, world.player.ammo)))
for char in String(ammo).reversed() {
let index = Int(char.asciiValue!) - 48
let step = Int(charSize.x)
let xRange = index * step ..< (index + 1) * step
offset.x -= charSize.x * hudScale
bitmap.drawImage(font, xRange: xRange, at: offset, size: charSize * hudScale)
}

// Weapon icon
let weaponIcon = textures[world.player.weapon.attributes.hudIcon]
offset.x -= weaponIcon.size.x * hudScale
bitmap.drawImage(weaponIcon, at: offset, size: weaponIcon.size * hudScale)

// Effects
for effect in world.effects {
switch effect.type {
Expand Down

0 comments on commit 3a5771d

Please sign in to comment.