Compare commits

..

No commits in common. 'master' and 'tiles_moving_bad' have entirely different histories.

File diff suppressed because one or more lines are too long

@ -2,22 +2,10 @@
"infinite":false, "infinite":false,
"layers":[ "layers":[
{ {
"data":[10, 14, 14, 14, 2684354570, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2684354573, 14, 14, 14, 1610612749, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2684354573, 14, 14, 14, 1610612749, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2684354573, 14, 14, 14, 1610612749, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2684354578, 13, 13, 13, 1610612752, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "data":[1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"height":12, "height":12,
"id":1, "id":1,
"name":"Ground", "name":"Tile Layer 1",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":24,
"x":0,
"y":0
},
{
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"height":12,
"id":2,
"name":"Wall",
"opacity":1, "opacity":1,
"type":"tilelayer", "type":"tilelayer",
"visible":true, "visible":true,
@ -25,7 +13,7 @@
"x":0, "x":0,
"y":0 "y":0
}], }],
"nextlayerid":3, "nextlayerid":2,
"nextobjectid":1, "nextobjectid":1,
"orientation":"orthogonal", "orientation":"orthogonal",
"renderorder":"left-down", "renderorder":"left-down",
@ -35,7 +23,7 @@
{ {
"columns":3, "columns":3,
"firstgid":1, "firstgid":1,
"image":"..\/..\/MonogameTest\/Maps\/pondv2.bmp", "image":"pond.png",
"imageheight":97, "imageheight":97,
"imagewidth":97, "imagewidth":97,
"margin":0, "margin":0,
@ -44,19 +32,6 @@
"tilecount":9, "tilecount":9,
"tileheight":32, "tileheight":32,
"tilewidth":32 "tilewidth":32
},
{
"columns":3,
"firstgid":10,
"image":"..\/..\/Tilemaps\/grass.png",
"imageheight":96,
"imagewidth":96,
"margin":0,
"name":"grass",
"spacing":0,
"tilecount":9,
"tileheight":32,
"tilewidth":32
}], }],
"tilewidth":32, "tilewidth":32,
"type":"map", "type":"map",

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="nunit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../SeeNoEvil/SeeNoEvil.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,18 @@
using NUnit.Framework;
namespace SeeNoEvil.Tests
{
public class Tests
{
[SetUp]
public void Setup()
{
}
[Test]
public void Test1()
{
Assert.Pass();
}
}
}

@ -1,140 +0,0 @@
{
"name": "cat",
"image": "Master-no-background-01",
"width": 32,
"height": 32,
"animations": [
{
"id": 1,
"name": "Walk Left",
"frames": [
{
"id": 1,
"x": 32,
"y": 64,
"timer": 8
},
{
"id": 2,
"x": 64,
"y": 64,
"timer": 8
},
{
"id": 3,
"x": 0,
"y": 64,
"timer": 8
}
]
},
{
"id": 2,
"name": "Walk Right",
"frames": [
{
"id": 1,
"x": 32,
"y": 96,
"timer": 8
},
{
"id": 2,
"x": 64,
"y": 96,
"timer": 8
},
{
"id": 3,
"x": 0,
"y": 96,
"timer": 8
}
]
},
{
"id": 3,
"name": "Walk Up",
"frames": [
{
"id": 1,
"x": 32,
"y": 128,
"timer": 6
},
{
"id": 2,
"x": 0,
"y": 128,
"timer": 6
}
]
},
{
"id": 4,
"name": "Walk Down",
"frames": [
{
"id": 1,
"x": 32,
"y": 160,
"timer": 6
},
{
"id": 2,
"x": 0,
"y": 160,
"timer": 6
}
]
},
{
"id": 5,
"name": "Scared Left",
"frames": [
{
"id": 1,
"x": 96,
"y": 64,
"timer": 0
}
]
},
{
"id": 6,
"name": "Scared Right",
"frames": [
{
"id": 1,
"x": 96,
"y": 96,
"timer": 0
}
]
},
{
"id": 7,
"name": "Scared Up",
"frames": [
{
"id": 1,
"x": 64,
"y": 128,
"timer": 0
}
]
},
{
"id": 8,
"name": "Scared Down",
"frames": [
{
"id": 1,
"x": 64,
"y": 160,
"timer": 0
}
]
}
]
}

@ -1,80 +0,0 @@
{
"name": "ghost",
"image": "Master-no-background-01",
"width": 32,
"height": 32,
"animations": [
{
"id": 1,
"name": "Walk Left",
"frames": [
{
"id": 1,
"x": 0,
"y": 32,
"timer": 6
},
{
"id": 2,
"x": 32,
"y": 32,
"timer": 6
}
]
},
{
"id": 2,
"name": "Walk Right",
"frames": [
{
"id": 1,
"x": 0,
"y": 0,
"timer": 6
},
{
"id": 2,
"x": 32,
"y": 0,
"timer": 6
}
]
},
{
"id": 3,
"name": "Walk Up",
"frames": [
{
"id": 1,
"x": 64,
"y": 0,
"timer": 6
},
{
"id": 2,
"x": 64,
"y": 32,
"timer": 6
}
]
},
{
"id": 4,
"name": "Walk Down",
"frames": [
{
"id": 1,
"x": 96,
"y": 0,
"timer": 6
},
{
"id": 2,
"x": 96,
"y": 32,
"timer": 6
}
]
}
]
}

@ -1,86 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace SeeNoEvil.Character {
public class AnimationController {
public string Name {get; private set;}
public string Image {get; private set;}
public int Width {get; private set;}
public int Height {get; private set;}
public bool Idle;
public Dictionary<int, Animation> Animations {get; private set;}
private Animation CurrentAnimation;
public Frame CurrentFrame {
get {
if(Idle) return CurrentAnimation.CurrentFrame;
else return CurrentAnimation.GetFrame();
}
}
public AnimationController(AnimationSetModel model) {
Name = model.Name;
Image = model.Image;
Width = model.Width;
Height = model.Height;
Animations = model.Animations.Aggregate(new Dictionary<int, Animation>(),
(animations, animation) => {
animations.Add(animation.Id, new Animation(animation));
return animations;
});
ChangeAnimation(1);
Idle = true;
}
public void ChangeAnimation(int animationId) {
if(Animations.TryGetValue(animationId, out CurrentAnimation))
CurrentAnimation.Reset();
}
}
public class Animation {
public int Id {get; set;}
public string Name {get; set;}
public FrameCollection Frames {get; set;}
public Frame CurrentFrame;
private int TotalFrames;
private int CurrentFrameId;
public Animation(AnimationModel model) {
Id = model.Id;
Name = model.Name;
Frames = new FrameCollection(model.Frames);
TotalFrames = model.Frames.Count();
}
public void Reset() {
CurrentFrameId = 1;
CurrentFrame = Frames[CurrentFrameId];
}
// TODO Is this super fuckin ugly? Seems like it
public Frame GetFrame() {
Frame result = CurrentFrame;
if(CurrentFrame.Timer == 1) {
CurrentFrameId = CurrentFrameId == TotalFrames ? 1 : CurrentFrameId + 1;
CurrentFrame = Frames[CurrentFrameId];
} else if(CurrentFrame.Timer > 1) CurrentFrame.Timer--;
return result;
}
}
public class FrameCollection {
private IEnumerable<Frame> Frames;
public Frame this[int i] {
get {
return Frames.Where(item => item.Id == i).First();
}
}
public FrameCollection(IEnumerable<Frame> frames) {
Frames = frames;
}
}
}

@ -1,24 +0,0 @@
using System.Collections.Generic;
namespace SeeNoEvil.Character {
public struct AnimationSetModel {
public string Name {get; set;}
public string Image {get; set;}
public int Width {get; set;}
public int Height {get; set;}
public IEnumerable<AnimationModel> Animations {get; set;}
}
public struct AnimationModel {
public int Id {get; set;}
public string Name {get; set;}
public IEnumerable<Frame> Frames{get; set;}
}
public struct Frame {
public int Id {get; set;}
public int X {get; set;}
public int Y {get; set;}
public int Timer {get; set;}
}
}

@ -1,15 +0,0 @@
using System.IO;
using System.Text.Json;
namespace SeeNoEvil.Character {
public static class AnimationParser {
public static AnimationSetModel ReadAnimationJson(string fileName) {
StreamReader streamReader = File.OpenText(fileName);
string text = streamReader.ReadToEnd();
var options = new JsonSerializerOptions {
PropertyNameCaseInsensitive = true,
};
return JsonSerializer.Deserialize<AnimationSetModel>(text, options);
}
}
}

@ -1,76 +0,0 @@
using Microsoft.Xna.Framework;
namespace SeeNoEvil.Character {
public class Cat : Character {
public Cat(Vector2 position, Direction facing) : base(position) {
AnimationController = new AnimationController(AnimationParser.ReadAnimationJson("SeeNoEvil/Animation/cat.json"));
Width = AnimationController.Width;
Height = AnimationController.Height;
Facing = facing;
ChooseAnimation(Facing);
}
public override void Move(Direction direction) {
if(!Moving) {
ChooseAnimation(direction);
base.Move(direction);
}
}
public Vector2 GetSight() {
Vector2 sight = Position;
for(int i = 0; i <= 9; i++) {
switch(Facing) {
case Direction.Up:
sight.Y -= Height;
break;
case Direction.Down:
sight.Y += Height;
break;
case Direction.Left:
sight.X -= Width;
break;
case Direction.Right:
sight.X += Width;
break;
}
if(!Field.TryWalk(sight)) break;
}
return sight;
}
public void ChooseAnimation(Direction direction) {
switch(direction) {
case Direction.Up:
AnimationController.ChangeAnimation(3);
break;
case Direction.Down:
AnimationController.ChangeAnimation(4);
break;
case Direction.Left:
AnimationController.ChangeAnimation(1);
break;
case Direction.Right:
AnimationController.ChangeAnimation(2);
break;
}
}
public void Scared() {
switch(Facing) {
case Direction.Up:
AnimationController.ChangeAnimation(7);
break;
case Direction.Down:
AnimationController.ChangeAnimation(8);
break;
case Direction.Left:
AnimationController.ChangeAnimation(5);
break;
case Direction.Right:
AnimationController.ChangeAnimation(6);
break;
}
}
}
}

@ -1,94 +0,0 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using SeeNoEvil.Level;
namespace SeeNoEvil.Character {
public class Character {
private Vector2 Destination {get; set;}
private Vector2 Velocity {get; set;}
public Vector2 Position {get; private set;}
private Texture2D SpriteSheet;
protected Vector2 StartingPosition;
protected AnimationController AnimationController;
protected int Width;
protected int Height;
protected PlayField Field;
public Direction Facing;
public bool Moving =>
!Destination.Equals(Vector2.Zero) &&
!Velocity.Equals(Vector2.Zero) &&
!Position.Equals(Destination);
public Character(Vector2 position) {
Position = position;
StartingPosition = position;
Destination = Vector2.Zero;
Velocity = Vector2.Zero;
}
public void Load(ContentManager content, PlayField playField) {
SpriteSheet = content.Load<Texture2D>(AnimationController.Image);
Field = playField;
}
// TODO Do I want to move every frame?
public void Update() {
if(Moving) {
Position = Vector2.Add(Position, Velocity);
AnimationController.Idle = false;
}
else AnimationController.Idle = true;
}
public void Draw(SpriteBatch spriteBatch) {
Frame currentFrame = AnimationController.CurrentFrame;
Rectangle srcRectangle = new Rectangle(currentFrame.X,
currentFrame.Y,
AnimationController.Width,
AnimationController.Height);
spriteBatch.Draw(SpriteSheet, Position, srcRectangle, Color.White);
}
public virtual void Move(Direction direction) {
if(!Moving) {
int velocity = 16;
int x = 0, y = 0;
switch(direction) {
case Direction.Up:
y = -1;
break;
case Direction.Down:
y = 1;
break;
case Direction.Left:
x = -1;
break;
case Direction.Right:
x = 1;
break;
}
var tryPosition = Vector2.Add(Position, new Vector2(Width*x, Height*y));
if(Field.TryWalk(tryPosition)) {
Destination = Vector2.Add(Position, new Vector2(Width*x, Height*y));
Velocity = new Vector2(x*velocity, y*velocity);
Facing = direction;
}
}
}
public void Reset() {
Position = StartingPosition;
Destination = Vector2.Zero;
Velocity = Vector2.Zero;
}
}
public enum Direction {
Up,
Down,
Left,
Right
}
}

@ -1,81 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using SeeNoEvil.Level;
using SeeNoEvil.Tiled;
namespace SeeNoEvil.Character {
public class GhostController {
public List<Ghost> Ghosts {get; set;}
public GhostController(IEnumerable<ObjectCoordinate> coordinates) {
Ghosts = coordinates.Select(
coord => new Ghost(new Vector2(coord.X, coord.Y))
).ToList();
}
public void LoadAll(ContentManager content, PlayField playField) =>
Ghosts.ForEach(ghost => ghost.Load(content, playField));
public void DrawAll(SpriteBatch spriteBatch) =>
Ghosts.ForEach(ghost => ghost.Draw(spriteBatch));
public void UpdateAll() =>
Ghosts.ForEach(ghost => ghost.Update());
public void MoveGhosts() =>
Ghosts.ForEach(ghost => ghost.DecideMove());
public bool AreGhostsHere(Vector2 playerPosition, Vector2 playerSight, Direction direction) =>
Ghosts.Any(ghost => ghost.IsInSight(playerPosition, playerSight, direction));
}
public class Ghost : Character {
public Ghost(Vector2 position) : base(position) {
AnimationController = new AnimationController(AnimationParser.ReadAnimationJson("SeeNoEvil/Animation/ghost.json"));
Width = AnimationController.Width;
Height = AnimationController.Height;
Facing = Direction.Down;
}
public void DecideMove() {
Array values = Enum.GetValues(typeof(Direction));
Random random = new Random();
Direction randomDirection = (Direction)values.GetValue(random.Next(values.Length));
switch(randomDirection) {
case Direction.Up:
AnimationController.ChangeAnimation(3);
break;
case Direction.Down:
AnimationController.ChangeAnimation(4);
break;
case Direction.Left:
AnimationController.ChangeAnimation(1);
break;
case Direction.Right:
AnimationController.ChangeAnimation(2);
break;
}
base.Move(randomDirection);
}
// FIXME it's a bit better now but still
public bool IsInSight(Vector2 playerPosition, Vector2 playerSight, Direction direction) {
if(direction == Direction.Up)
return playerPosition.X == Position.X &&
(playerPosition.Y > Position.Y) && (Position.Y > playerSight.Y);
else if(direction == Direction.Down)
return playerPosition.X == Position.X &&
(playerPosition.Y < Position.Y) && (Position.Y < playerSight.Y);
else if(direction == Direction.Left)
return playerPosition.Y == Position.Y &&
(playerPosition.X > Position.X) && (Position.X > playerSight.X);
else
return playerPosition.Y == Position.Y &&
(playerPosition.X < Position.X) && (Position.X < playerSight.X);
}
}
}

@ -0,0 +1,80 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using SeeNoEvil.Tiled;
using SeeNoEvil.Level;
namespace SeeNoEvil
{
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
TilemapLevel level;
Dictionary<string, Texture2D> tilesets;
Camera viewport;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
viewport.height = 720;
viewport.width = 1280;
viewport.x = 0;
viewport.y = 0;
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
level = new TilemapLevel("./Maps/MagicLandCsv.json");
level.LoadMap();
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
tilesets = new Dictionary<string, Texture2D>();
tilesets = level.GetTilesetNames().Aggregate(new Dictionary<string, Texture2D>(),
(content, contentName) => {
content.Add(contentName, Content.Load<Texture2D>(contentName));
return content;
});
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
if(Keyboard.GetState().IsKeyDown(Keys.Down))
viewport.y += 16;
if(Keyboard.GetState().IsKeyDown(Keys.Up))
viewport.y -= 16;
if(Keyboard.GetState().IsKeyDown(Keys.Left))
viewport.x -= 16;
if(Keyboard.GetState().IsKeyDown(Keys.Right))
viewport.x += 16;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
level.Draw(viewport, spriteBatch, tilesets);
spriteBatch.End();
base.Draw(gameTime);
}
}
}

@ -1,27 +1,21 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace SeeNoEvil.Level { namespace SeeNoEvil.Level {
public class Camera { public struct Camera {
public Matrix Transform {get; private set;} public int width;
public Viewport Viewport {get; private set;} public int height;
public Vector2 Centre {get; set;} public int x;
public int y;
}
private Vector3 TranslationVector => // public class Camera {
new Vector3(-Centre.X + (Viewport.Width / 2), // private Viewport m_dimension;
-Centre.Y + (Viewport.Height / 2),
1);
public Camera(Viewport _viewport) { // public Camera(int x, int y) {
Viewport = _viewport; // m_dimension.x = x;
//TODO This is to experiment // m_dimension.y = x;
Centre = new Vector2(Viewport.Width / 2, Viewport.Height / 2); // }
}
//FIXME Don't need velocity anymore? // public Viewport GetDimension() {
public void Update(Vector2 position) { // return m_dimension;
Centre = position; // }
Transform = Matrix.CreateTranslation(TranslationVector); // }
}
}
} }

@ -1,60 +1,32 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using SeeNoEvil.Tiled;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using SeeNoEvil.Tiled;
namespace SeeNoEvil.Level { namespace SeeNoEvil.Level {
public class TilemapLevel { public class TilemapLevel {
private readonly string MapName; private readonly string MapName;
private TiledMap Map; private TiledMap Map;
private Dictionary<string, Texture2D> TilesetTextures;
public TilemapLevel(string tilemapName) { public TilemapLevel(string tilemapName) {
MapName = tilemapName; MapName = tilemapName;
} }
public void LoadMap(ContentManager content) { public void LoadMap() {
Map = new TiledMap(TiledParser.ReadMapJson(MapName)); Map = TiledParser.ReadMapJson(MapName);
Map.LoadView();
Map.LoadObjects();
TilesetTextures = Map.GetTilesetNames().Aggregate(new Dictionary<string, Texture2D>(),
(textures, contentName) => {
textures.Add(contentName, content.Load<Texture2D>(contentName));
return textures;
});
}
private IEnumerable<string> GetTilesetNames() => Map.GetTilesetNames();
public Vector2 GetPlayerPosition() {
//FIXME This fuckin sucks
Map.Objects.TryGetValue("Cat", out List<ObjectCoordinate> catCoords);
ObjectCoordinate catCoord = catCoords.First();
return new Vector2(catCoord.X, catCoord.Y);
}
public PlayField GetPlayField() {
Map.View.TryGetValue("Ground", out List<TileLocation> ground);
return new PlayField(ground);
} }
public IEnumerable<ObjectCoordinate> GetGhostCoordinates() { public IEnumerable<string> GetTilesetNames() {
// FIXME this fuckin sucks too I think? return Map.GetTilesetNames();
Map.Objects.TryGetValue("Ghosts", out List<ObjectCoordinate> ghosts);
return ghosts;
} }
public void Draw(SpriteBatch spriteBatch, string layer) { public void Draw(Camera viewport, SpriteBatch spritebatch, IDictionary<string, Texture2D> this_sucks) {
List<TileLocation> locations; IEnumerable<TileLocation> locations = Map.DrawView(viewport);
if(Map.View.TryGetValue(layer, out locations)) locations.ToList().ForEach(tile => {
locations.ForEach(tile => { Texture2D this_one;
Texture2D layerTexture; if(tile.tile.gid > 0 && this_sucks.TryGetValue(tile.tile.setName, out this_one)) {
if(tile.tile.gid > 0 && TilesetTextures.TryGetValue(tile.tile.setName, out layerTexture)) { spritebatch.Draw(this_one, tile.location, tile.tile.srcRectangle, Color.White);
spriteBatch.Draw(layerTexture, tile.location, tile.tile.srcRectangle, Color.White);
} }
}); });
} }

@ -1,20 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using SeeNoEvil.Tiled;
namespace SeeNoEvil.Level {
public class PlayField {
private IEnumerable<TileLocation> Tiles {get; set;}
public PlayField(IEnumerable<TileLocation> tiles) {
Tiles = tiles;
}
public bool TryWalk(Vector2 newLocation) =>
Tiles.Any(tile => tile.location.Equals(newLocation) && tile.tile.gid != 0);
private bool Between(float pos1, float pos2, float bound) =>
(bound - pos1) >= (pos2 - pos1);
}
}

@ -7,7 +7,7 @@ namespace SeeNoEvil
[STAThread] [STAThread]
static void Main() static void Main()
{ {
using (var game = new SeeNoEvilGame()) using (var game = new Game1())
game.Run(); game.Run();
} }
} }

@ -1,110 +0,0 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using SeeNoEvil.Level;
using SeeNoEvil.Character;
namespace SeeNoEvil
{
public class SeeNoEvilGame : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
TilemapLevel level;
Camera camera;
Cat player;
GhostController enemyController;
PlayField playField;
bool scared;
int scaredTimer = 0;
Ghost debugGhost;
public SeeNoEvilGame()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
debugGhost = null;
}
protected override void Initialize()
{
// level = new TilemapLevel("./Maps/MagicLandCsv.json");
// level = new TilemapLevel("./Maps/test.json");
level = new TilemapLevel("./Maps/level.json");
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
level.LoadMap(Content);
playField = level.GetPlayField();
player = new Cat(level.GetPlayerPosition(), Direction.Right);
player.Load(Content, playField);
enemyController = new GhostController(level.GetGhostCoordinates());
enemyController.LoadAll(Content, playField);
camera = new Camera(GraphicsDevice.Viewport);
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
if(scaredTimer == 0) {
if(Keyboard.GetState().IsKeyDown(Keys.Down)) {
player.Move(Direction.Down);
enemyController.MoveGhosts();
}
if(Keyboard.GetState().IsKeyDown(Keys.Up)) {
player.Move(Direction.Up);
enemyController.MoveGhosts();
}
if(Keyboard.GetState().IsKeyDown(Keys.Left)) {
player.Move(Direction.Left);
enemyController.MoveGhosts();
}
if(Keyboard.GetState().IsKeyDown(Keys.Right)) {
player.Move(Direction.Right);
enemyController.MoveGhosts();
}
player.Update();
enemyController.UpdateAll();
camera.Update(player.Position);
if(!player.Moving) {
scared = enemyController.AreGhostsHere(player.Position, player.GetSight(), player.Facing);
}
if(scared) {
player.Scared();
scaredTimer = 60;
}
} else if(scaredTimer == 1) {
scared = false;
player.Reset();
player.ChooseAnimation(player.Facing);
scaredTimer = 0;
} else scaredTimer--;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(
transformMatrix: camera.Transform
);
level.Draw(spriteBatch, "Sky");
level.Draw(spriteBatch, "Ground");
level.Draw(spriteBatch, "Bushes");
player.Draw(spriteBatch);
enemyController.DrawAll(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
}

@ -1,40 +0,0 @@
// TODO Handle flipped tiles!
using System.Collections.Generic;
using System.Linq;
using SeeNoEvil.Level;
namespace SeeNoEvil.Tiled {
public class TileLayer {
public string Type {get; private set;}
public string Name {get; private set;}
public readonly List<DataCoordinate> DataCoordinates = new List<DataCoordinate>();
private int Width;
private int Height;
private List<uint> Data;
public TileLayer(MapLayerModel model) {
Name = model.Name;
Width = model.Width;
Height = model.Height;
Type = model.Type;
if(model.Type == "tilelayer") {
Data = model.Data.ToList();
BuildCoordinates();
}
}
private void BuildCoordinates() {
int row = 0;
int column = 0;
Data.ForEach(gid => {
DataCoordinates.Add(new DataCoordinate(column, row, gid));
if(column == Width-1) {
row++;
column = 0;
} else column++;
});
}
}
}

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
//TODO Do all these need to be public?
namespace SeeNoEvil.Tiled {
//TODO Can probably be a struct?
public class ObjectLayer {
public IEnumerable<ObjectCoordinate> Objects {get; private set;}
public string Name {get; private set;}
public ObjectLayer(MapLayerModel model) {
Name = model.Name;
Objects = model.Objects.Select(o => new ObjectCoordinate(o.Id,
o.X,
o.Y));
}
}
public struct ObjectCoordinate {
public ObjectCoordinate(int id, float x, float y) {
X = (int)Math.Round(x / 32)*32;
Y = (int)Math.Round(y / 32)*32;
Id = id;
}
public int X {get; set;}
public int Y {get; set;}
public int Id {get; set;}
}
}

@ -1,77 +0,0 @@
using System.Collections.Generic;
using Microsoft.Xna.Framework;
namespace SeeNoEvil.Tiled {
public class TileSet {
private string Image {get; set;}
private string Name {get; set;}
private int ImageHeight {get; set;}
private int ImageWidth {get; set;}
private int TileHeight {get; set;}
private int TileWidth {get; set;}
private int Spacing {get; set;}
private int Columns {get; set;}
private int FirstGid {get; set;}
private int TileCount {get; set;}
private Dictionary<uint, Tile> Tiles {get; set;}
private bool TilesLoaded {get; set;}
public TileSet(TileSetModel model) {
Image = model.Image;
Name = model.Name;
ImageHeight = model.ImageHeight;
ImageWidth = model.ImageWidth;
TileHeight = model.TileHeight;
TileWidth = model.TileWidth;
Spacing = model.Spacing;
Columns = model.Columns;
FirstGid = model.FirstGid;
TileCount = model.TileCount;
Tiles = new Dictionary<uint, Tile>();
TilesLoaded = false;
}
public bool ContainsTile(uint gid) =>
!(gid < FirstGid || gid > (FirstGid + TileCount - 1));
public Tile GetTile(uint gid) {
if(!TilesLoaded) LoadTiles();
Tile result;
Tiles.TryGetValue(gid, out result);
return result;
}
public string GetContentName() {
return Name;
}
private void LoadTiles() {
Tiles = new Dictionary<uint, Tile>();
int row = 0;
int rowPx = 0;
int column = 0;
int columnPx = 0;
for(int i = 0; i < TileCount; i++) {
Rectangle rectangle = new Rectangle(
columnPx,
rowPx,
TileWidth,
TileHeight
);
uint gid = (uint)(i + FirstGid);
Tiles.Add(gid, new Tile(gid, rectangle, Name));
if(column == Columns-1) {
row++;
rowPx += Spacing + TileHeight;
column = 0;
columnPx = 0;
} else {
column++;
columnPx += Spacing + TileWidth;
}
}
TilesLoaded = true;
}
}
}

@ -2,71 +2,56 @@ using System.Collections.Generic;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using System.Linq; using System.Linq;
using SeeNoEvil.Level; using SeeNoEvil.Level;
using System.Text.Json.Serialization;
namespace SeeNoEvil.Tiled { namespace SeeNoEvil.Tiled {
public class TiledMap { public class TiledMap {
public Dictionary<string, List<TileLocation>> View {get; private set;} public TiledMap() => TileCache = new Dictionary<uint, Tile>();
public Dictionary<string, List<ObjectCoordinate>> Objects {get; private set;}
private bool Infinite;
private List<TileLayer> TileLayers;
private List<ObjectLayer> ObjectLayers;
private List<TileSet> TileSets;
private int TileHeight;
private int TileWidth;
private int Rows;
private int Columns;
// TODO Do I really need this?
private Dictionary<uint, Tile> TileCache;
public TiledMap(TiledModel model) {
Infinite = model.Infinite;
TileLayers = model.Layers.Where(model => model.Type == "tilelayer")
.Select(model => new TileLayer(model)).ToList();
ObjectLayers = model.Layers.Where(model => model.Type == "objectgroup")
.Select(model => new ObjectLayer(model)).ToList();
TileSets = model.TileSets.Select(model => new TileSet(model)).ToList();
TileHeight = model.TileHeight;
TileWidth = model.TileWidth;
Rows = model.Height;
Columns = model.Width;
TileCache = new Dictionary<uint, Tile>();
View = new Dictionary<string, List<TileLocation>>();
}
public IEnumerable<string> GetTilesetNames() => public bool Infinite {get; set;}
TileSets.Select(tileset => tileset.GetContentName()); public IEnumerable<MapLayer> Layers {get; set;}
public IEnumerable<TileSet> TileSets {get; set;}
public int TileHeight {get; set;}
public int TileWidth {get; set;}
private Dictionary<uint, Tile> TileCache {get; set;}
// Load Tile Locations for each layer public IEnumerable<TileLocation> DrawView(Camera viewport) {
public void LoadView() { Dictionary<string, IEnumerable<DataCoordinate>> layerData = new Dictionary<string, IEnumerable<DataCoordinate>>();
// Get all tilelayers Layers.Where(layer => layer.Type == "tilelayer").ToList()
Dictionary<string, List<DataCoordinate>> layerData = new Dictionary<string, List<DataCoordinate>>();
TileLayers.Where(layer => layer.Type == "tilelayer").ToList()
.ForEach(layer => { .ForEach(layer => {
layerData.Add(layer.Name, layer.DataCoordinates); layerData.Add(layer.Name, layer.GetVisibleTiles(viewport, TileHeight, TileWidth));
}); });
HashSet<uint> gids = layerData.Aggregate(new HashSet<uint>(),
// Get all required unique gids and load to cache
LoadTiles(layerData.Aggregate(new HashSet<uint>(),
(tiles, layer) => { (tiles, layer) => {
foreach(var tile in layer.Value) { layer.Value.ToList().ForEach(tile => tiles.Add(tile.gid));
tiles.Add(tile.gid);
}
return tiles; return tiles;
}) });
); IDictionary<uint, Tile> tiles = GetTilesetTiles(gids);
// return layerData.Aggregate(new List<TileLocation>(),
// build resulting tile location collection for each layer // (locations, layer) => {
View = layerData.Aggregate(new Dictionary<string, List<TileLocation>>(), // layer.Value.ToList().ForEach(coord => {
(locations, layer) => { // Tile currTile;
// if(!tiles.TryGetValue(coord.gid, out currTile)) {
// currTile = new Tile();
// }
// Vector2 pxLocation = new Vector2(coord.x*TileWidth, coord.y*TileHeight);
// locations.Add(new TileLocation(currTile, pxLocation));
// });
// return locations;
// });
int column = 0, row = 0, columnPx = 0, rowPx = 0; int column = 0, row = 0, columnPx = 0, rowPx = 0;
var layerLocations = new List<TileLocation>(); int viewportRows = viewport.height / TileHeight;
layer.Value.ForEach(coord => { int viewportColumns = viewport.width / TileWidth;
Tile currTile = new Tile(); return layerData.Aggregate(new List<TileLocation>(),
if(coord.gid > 0) (locations, layer) => {
TileCache.TryGetValue(coord.gid, out currTile); layer.Value.ToList().ForEach(coord => {
Tile currTile;
if(!tiles.TryGetValue(coord.gid, out currTile)) {
currTile = new Tile();
}
Vector2 pxLocation = new Vector2(columnPx, rowPx); Vector2 pxLocation = new Vector2(columnPx, rowPx);
layerLocations.Add(new TileLocation(currTile, pxLocation)); locations.Add(new TileLocation(currTile, pxLocation));
if(column == (Columns-1)) { if(column == viewportColumns) {
row++; row++;
rowPx += TileHeight; rowPx += TileHeight;
column = columnPx = 0; column = columnPx = 0;
@ -75,32 +60,175 @@ namespace SeeNoEvil.Tiled {
columnPx += TileWidth; columnPx += TileWidth;
} }
}); });
locations.Add(layer.Key, layerLocations);
return locations; return locations;
}); });
} }
// Load objects on the level public IEnumerable<string> GetTilesetNames() =>
public void LoadObjects() { TileSets.Aggregate(new List<string>(),
Objects = ObjectLayers.Aggregate(new Dictionary<string, List<ObjectCoordinate>>(), (names, tileset) => {
// FIXME This is stupid naming names.Add(tileset.GetContentName());
(layers, objects) => { return names;
layers.Add(objects.Name, objects.Objects.ToList()); });
return layers;
private IDictionary<uint, Tile> GetTilesetTiles(HashSet<uint> tiles) {
Dictionary<uint, Tile> loadedTiles = new Dictionary<uint, Tile>();
tiles.ToList().ForEach(gid => {
TileSet tileset = TileSets.FirstOrDefault(set => set.ContainsTile(gid));
Tile tile = tileset == null ? new Tile() : tileset.GetTile(gid);
loadedTiles.Add(gid, tile);
});
return loadedTiles;
}
}
public struct TileLocation {
public TileLocation(Tile tile, Vector2 location) {
this.tile = tile;
this.location = location;
}
public Tile tile;
public Vector2 location;
} }
public struct Tile {
public Tile(long _gid, Rectangle _srcRectangle, string _setName) {
gid = (uint)_gid;
srcRectangle = _srcRectangle;
setName = _setName;
}
public uint gid;
public Rectangle srcRectangle;
public string setName;
}
public class TileSet {
public TileSet() {
TilesLoaded = false;
}
public string Image {get; set;}
public string Name {get; set;}
public int ImageHeight {get; set;}
public int ImageWidth {get; set;}
public int TileHeight {get; set;}
public int TileWidth {get; set;}
public int Spacing {get; set;}
public int Columns {get; set;}
public int FirstGid {get; set;}
public int TileCount {get; set;}
private IDictionary<uint, Tile> Tiles {get; set;}
private bool TilesLoaded {get; set;}
public Tile GetTile(uint gid) {
if(!TilesLoaded) {
LoadTiles();
}
Tile result;
Tiles.TryGetValue(gid, out result);
return result;
}
public bool ContainsTile(uint gid) {
return !(gid < FirstGid ||
gid > (FirstGid + TileCount - 1));
}
public string GetContentName() {
return Name;
}
private void LoadTiles() {
Tiles = new Dictionary<uint, Tile>();
int row = 0;
int rowPx = 0;
int column = 0;
int columnPx = 0;
for(int i = 0; i < TileCount; i++) {
Rectangle rectangle = new Rectangle(
columnPx,
rowPx,
TileWidth,
TileHeight
); );
uint gid = (uint)(i + FirstGid);
Tiles.Add(gid, new Tile(gid, rectangle, Name));
if(column == Columns-1) {
row++;
rowPx += Spacing + TileHeight;
column = 0;
columnPx = 0;
} else {
column++;
columnPx += Spacing + TileWidth;
}
} }
// Load tiles into cache if they don't exist TilesLoaded = true;
private void LoadTiles(HashSet<uint> tiles) {
foreach(uint gid in tiles) {
if(!TileCache.ContainsKey(gid)) {
TileSet tileset = TileSets.FirstOrDefault(set => set.ContainsTile(gid));
Tile tile = tileset == null ? new Tile() : tileset.GetTile(gid);
TileCache.Add(gid, tile);
} }
} }
public struct DataCoordinate {
public DataCoordinate(int _x, int _y, uint _gid) {
x = _x;
y = _y;
gid = _gid;
} }
public int x;
public int y;
public uint gid;
} }
public class MapLayer {
public MapLayer() { }
public string Name {get; set;}
public int Width {get; set;}
public int Height {get; set;}
public IEnumerable<uint> Data {get; set;}
public string Type {get; set;}
public IEnumerable<DataCoordinate> DataCoordinates {get; set;}
public bool BuiltCoordinates {get; private set;}
public IEnumerable<DataCoordinate> GetVisibleTiles(Camera viewport, int tileHeight, int tileWidth) {
if(!BuiltCoordinates) {
BuildCoordinates();
}
int startColumn = viewport.x / tileWidth;
int endColumn = startColumn + (viewport.width / tileWidth);
int startRow = viewport.y / tileHeight;
int endRow = startRow + (viewport.height / tileHeight);
var coords = DataCoordinates.Where(coord =>
startRow <= coord.y &&
endRow >= coord.y &&
startColumn <= coord.x &&
endColumn >= coord.x
).ToList();
return DataCoordinates.Where(coord =>
startRow <= coord.y &&
endRow >= coord.y &&
startColumn <= coord.x &&
endColumn >= coord.x
);
}
private void BuildCoordinates() {
int row = 0;
int column = 0;
List<DataCoordinate> coordinates = new List<DataCoordinate>();
Data.ToList().ForEach(gid => {
coordinates.Add(new DataCoordinate(column, row, gid));
if(column == Width-1) {
row++;
column = 0;
} else column++;
});
DataCoordinates = coordinates;
BuiltCoordinates = true;
}
}
} }

@ -1,41 +0,0 @@
using System.Collections.Generic;
namespace SeeNoEvil.Tiled {
public struct TiledModel {
public bool Infinite {get; set;}
public IEnumerable<MapLayerModel> Layers {get; set;}
public IEnumerable<TileSetModel> TileSets {get; set;}
public int TileHeight {get; set;}
public int TileWidth {get; set;}
public int Height {get; set;}
public int Width {get; set;}
}
public struct TileSetModel {
public string Image {get; set;}
public string Name {get; set;}
public int ImageHeight {get; set;}
public int ImageWidth {get; set;}
public int TileHeight {get; set;}
public int TileWidth {get; set;}
public int Spacing {get; set;}
public int Columns {get; set;}
public int FirstGid {get; set;}
public int TileCount {get; set;}
}
public struct MapLayerModel {
public string Name {get; set;}
public int Width {get; set;}
public int Height {get; set;}
public IEnumerable<uint> Data {get; set;}
public string Type {get; set;}
public IEnumerable<TiledObjectModel> Objects {get; set;}
}
public struct TiledObjectModel {
public int Id {get; set;}
public float X {get; set;}
public float Y {get; set;}
}
}

@ -3,13 +3,13 @@ using System.Text.Json;
namespace SeeNoEvil.Tiled { namespace SeeNoEvil.Tiled {
public static class TiledParser { public static class TiledParser {
public static TiledModel ReadMapJson(string fileName) { public static TiledMap ReadMapJson(string fileName) {
StreamReader streamReader = File.OpenText(fileName); StreamReader streamReader = File.OpenText(fileName);
string text = streamReader.ReadToEnd(); string text = streamReader.ReadToEnd();
var options = new JsonSerializerOptions { var options = new JsonSerializerOptions {
PropertyNameCaseInsensitive = true, PropertyNameCaseInsensitive = true,
}; };
return JsonSerializer.Deserialize<TiledModel>(text, options); return JsonSerializer.Deserialize<TiledMap>(text, options);
} }
} }
} }

@ -1,36 +0,0 @@
using Microsoft.Xna.Framework;
namespace SeeNoEvil.Tiled {
public struct Tile {
public Tile(long _gid, Rectangle _srcRectangle, string _setName) {
gid = (uint)_gid;
srcRectangle = _srcRectangle;
setName = _setName;
}
public uint gid;
public Rectangle srcRectangle;
public string setName;
}
public struct TileLocation {
public TileLocation(Tile tile, Vector2 location) {
this.tile = tile;
this.location = location;
}
public Tile tile;
public Vector2 location;
}
public struct DataCoordinate {
public DataCoordinate(int _x, int _y, uint _gid) {
x = _x;
y = _y;
gid = _gid;
}
public int x;
public int y;
public uint gid;
}
}
Loading…
Cancel
Save